package fms.controller;

import fms.dao.CptInfoService;
import fms.dao.Grib2InfoService;
import fms.dao.NaipService;
import fms.util.*;
import fms.webservice.*;
import fms.xml.WindRequestXML;
import fms.xml.WindResponseXML;
import org.apache.log4j.Logger;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by Administrator on 2014/8/28.
 */
public class Grib2Controller {
    private Logger logger = Logger.getLogger(Grib2Controller.class);
    private Logger windCalcLogger = Logger.getLogger("windCalc");

    // 提供数据库交互服务的对象
    private NaipService naipService = null;
    private Grib2InfoService grib2InfoService = null;
    private CptInfoService cptInfoService = null;

    public final String Grib2PointTableCPT = "CPTINFO";
    public final String Grib2PointTableNAIP = "NAIP";
    private String grib2PointTableName = "";

    /**
     * 构造函数
     */
    public Grib2Controller(String tableName) {
        grib2PointTableName = tableName;
        grib2InfoService = ConfUtil.getSingletonApplicationContextDao().getBean("grib2InfoService", Grib2InfoService.class);
        naipService = ConfUtil.getSingletonApplicationContextDao().getBean("naipService", NaipService.class);
        cptInfoService = ConfUtil.getSingletonApplicationContextDao().getBean("cptInfoService", CptInfoService.class);
    }


    /**
     * 根据航路点取得其经纬度
     *
     * @param cptname 航路点名称
     * @return
     */
    public List getLonAndLat(String cptname,String aircraftId,String flightId) {

        List<Double> returnList = new ArrayList<Double>();
        double lon = 0.0;
        double lat = 0.0;
        List data = null;

        //根据航路点名称、航班号取出经、纬度
        if (!ObjectUtil.isBlank(grib2PointTableName)
                && grib2PointTableName.equals(Grib2PointTableNAIP)) {
            // NAIP表 经纬度以“度、分、秒”的格式存放
            data = naipService.findCptPosByName(cptname);
        } else {
            // CPT_INFO表 经纬度以“度、分”的格式存放，其中“分”含有秒的小数表示
            data = cptInfoService.findByCptname(cptname, aircraftId, flightId);
        }

        if (data != null && data.size() != 0) {
            Object[] obj = (Object[]) data.get(0);
            if (!ObjectUtil.isBlank(grib2PointTableName)
                    && grib2PointTableName.equals(Grib2PointTableNAIP)) {
                lon = GribUtil.convertLonLat(obj[0].toString(), 1);
                lat = GribUtil.convertLonLat(obj[1].toString(), 1);
//                windCalcLogger.debug("[Grib2Controller-getLonAndLat] 航路点名称为：" + cptname + "，从NAIP表查询到经纬：lon（" + lon + "），lat（" + lat + "）");
            } else {
                lon = GribUtil.convertLonLat(obj[0].toString(), 2);
                lat = GribUtil.convertLonLat(obj[1].toString(), 2);
//                windCalcLogger.debug("[Grib2Controller-getLonAndLat] 航路点名称为：" + cptname + "，从CPT_INFO表查询到经纬：lon(" + lon + "），lat（" + lat + "）");
            }
//            System.out.println("lon:" + lon + "lat:" + lat);
        } else {
            logger.error("航路点名称为：" + cptname + " 在数据库中没有查询到！");
            return null;
        }
        returnList.add(lon);
        returnList.add(lat);
        return returnList;
    }

    /**
     * function : 取得给定点周围八个点的VGRD UGRD TMP信息
     * @param alt 高度
     * @return 一个包含了三个LIST的map；
     *         每个LIST包含了8个点 U or V or T 一种数据
     */
    public Map getEightPointsUVT(double lon, double lat, double alt) {
        Map returnMap = new HashMap();
        List ugrdList = new ArrayList();
        List vgrdList = new ArrayList();
        List tmpList = new ArrayList();

        // 根据经、纬度、高度取出8个点
        List pointList = GribUtil.getPointList(lon, lat, alt);
        // 取得给定经、纬、高度的8个点的UGRD、VGRD、TMP信息
        List valueList = grib2InfoService.findByLonLatAlt(GribUtil.getTwoStandardLons(lon),
                GribUtil.getTwoStandardLats(lat),
                GribUtil.getTwoStandardAltitudes(alt));
        if (valueList == null || valueList.size() != 24) {
            //数据库中的grid2数据不完整，直接返回
            logger.error("无法在数据库中查询到点（经度：" + lon + "，纬度：" + lat + "，高度层：" + alt + "）周围的8个格点grid2数据！");
            return null;
        }
        // 遍历pointList将URRD、VGRD、TMP数据放入三个list中
        for (int i = 0; i < pointList.size(); i++) {
            Object[] obj = (Object[]) pointList.get(i);
            double dLon = Double.valueOf(obj[0].toString());
            double dLat = Double.valueOf(obj[1].toString());
            int dAlt = Integer.parseInt(obj[2].toString());
            for (int j = 0; j < valueList.size(); j++) {
                Object[] objValue = (Object[]) valueList.get(j);
                if (dLon == Double.valueOf(objValue[0].toString())
                        && dLat == Double.valueOf(objValue[1].toString())
                        && dAlt == Integer.parseInt(objValue[2].toString())) {
                    PointVo pointVo = new PointVo();
                    pointVo.setdAlt(String.valueOf(dAlt));
                    pointVo.setdLat(String.valueOf(dLat));
                    pointVo.setdLon(String.valueOf(dLon));
                    pointVo.setWindVal(String.valueOf(objValue[3]));
                    if (("UGRD").equals(objValue[4])) {
                        ugrdList.add(pointVo);
                        // ugrdList.add(new Object[]{dLon, dLat, dAlt, objValue[3]});
                    } else if (("VGRD").equals(objValue[4])) {
                        vgrdList.add(pointVo);
                        //  vgrdList.add(new Object[]{dLon, dLat, dAlt, objValue[3]});
                    } else if (("TMP").equals(objValue[4])) {
                        tmpList.add(pointVo);
                        //  tmpList.add(new Object[]{dLon, dLat, dAlt, objValue[3]});
                    }
                }
            }
        }


        returnMap.put("UGRID", ugrdList);
        returnMap.put("VGRD", vgrdList);
        returnMap.put("TMP", tmpList);

        return returnMap;
    }

    /**
     * @param valueList 待求点周围的8个点，V or U or 温度值的值列表
     * @param lon       待求点经度
     * @param lat       待求点纬度
     * @param alt       待求点高度层
     * @return
     */
    public BigDecimal calcWindInfo(List valueList, double lon, double lat, double alt) {
        List list = new ArrayList();
        List altList = GribUtil.getTwoStandardAltitudes(alt);
        BigDecimal[] altObject = new BigDecimal[]{new BigDecimal(altList.get(0).toString()), new BigDecimal(altList.get(1).toString())};

        // 通过“冒泡比较”的方法：筛选出四组经纬度都相同且高度层不同的点，后再组内分别利用对数计算公式求目标点的值
        //  for (int i = 0; i < 4; i++) {
        for (int i = 0; i < valueList.size(); i++) {
            //  PointVo  pointUp = (PointVo) valueList.get(i);
            //   PointVo  pointDown = (PointVo) valueList.get(i + 4);
            for (int j = 0; j < valueList.size(); j++) {
                PointVo pointVo1 = (PointVo) valueList.get(i);
                PointVo pointVo2 = (PointVo) valueList.get(j);
                if (new BigDecimal(pointVo1.getdLon()).compareTo(new BigDecimal(pointVo2.getdLon())) == 0
                        && new BigDecimal(pointVo1.getdLat()).compareTo(new BigDecimal(pointVo2.getdLat())) == 0) {
                    PointVo pointUp = new PointVo();
                    PointVo pointDown = new PointVo();
                    PointVo newPoint = new PointVo();
                    if (Double.valueOf(pointVo1.getdAlt()) > Double.valueOf(pointVo2.getdAlt())) {
                        pointDown = pointVo2;
                        pointUp = pointVo1;
                        BigDecimal[] value = new BigDecimal[]{new BigDecimal(pointUp.getWindVal()), new BigDecimal(pointDown.getWindVal())};
                        BigDecimal[] calcValue = GribUtil.ComputeLogarithmValue(altObject, 2, value, new BigDecimal[]{new BigDecimal(alt)}, 1);

                        newPoint.setdLon(pointUp.getdLon());
                        newPoint.setdLat(pointUp.getdLat());
                        newPoint.setWindVal(String.valueOf(calcValue[0]));
                        list.add(newPoint);
                    }
                }
            }
        }
        // 对目标高度层上的四个经纬度相同的点进行分组，经度不同、纬度相同的为一组
        List lineList = new ArrayList();
        int temp = 0;
        for (int tempi = 0; tempi < list.size(); tempi++) {
            //避免重复
            if (temp != tempi) {
                for (int tempj = 0; tempj < list.size(); tempj++) {
                    PointVo vo1 = (PointVo) list.get(tempi);
                    PointVo vo2 = (PointVo) list.get(tempj);
                    if ((new BigDecimal(vo1.getdLon()).compareTo(new BigDecimal(vo2.getdLon())) != 0
                            && new BigDecimal(vo1.getdLat()).compareTo(new BigDecimal(vo2.getdLat())) == 0)) {
                        temp = tempj;
                        Map map = new HashMap();
                        map.put("P1", vo1);
                        map.put("P2", vo2);
                        lineList.add(map);
                    }
                }
            }
        }
        if (lineList.size() != 2) {
            logger.error("线性插值运算的两个点数目不正确！");
            return null;
        }
        return GribUtil.biLinearInterpolate(lineList, new BigDecimal(lon), new BigDecimal(lat));
    }

    /**
     * 计算指定高度层、经度、纬度的点的V/U/温度值
     */
    public String windCalculation(String cptName, double alt, String aircraftId, String flightId) {
        List lonLatList = new ArrayList();
        if (GribUtil.nameIsLonLat(cptName)) {
            logger.info(cptName + "是含有经纬度的航路点名称！");
            lonLatList = GribUtil.getLonLatList(cptName);
        } else {
            // 从数据库中查询当前航路点的经纬度
            lonLatList = getLonAndLat(cptName,aircraftId,flightId);
        }

        if (lonLatList != null) {
            double lon = Double.valueOf(lonLatList.get(0).toString());
            double lat = Double.valueOf(lonLatList.get(1).toString());

            // 获取指定“经纬度点、高度层”周围的八个“标准气压高度层、经纬度点”的UVT数据
            Map pointMap = getEightPointsUVT(lon, lat, alt);
            if (pointMap != null) {
                List ugrdList = (List) pointMap.get("UGRID");
                List vgrdList = (List) pointMap.get("VGRD");
                List tmpList = (List) pointMap.get("TMP");

                windCalcLogger.info("[Grib2Controller-windCalculation] - [开始] 计算指定航路点、高度层UVT分量：" + cptName + "（lon：" + lon + "，lat：" + lat + "，alt：" + alt + "）");

                BigDecimal uvalue = calcWindInfo(ugrdList, lon, lat, alt);
                BigDecimal vvalue = calcWindInfo(vgrdList, lon, lat, alt);
                BigDecimal tvalue = calcWindInfo(tmpList, lon, lat, alt);

                String returnStr = GribUtil.ComputeWindVelDirByUV(uvalue, vvalue);

                windCalcLogger.info("[Grib2Controller-windCalculation] - [结束] 计算指定航路点、高度层UVT分量：" + "u：" + uvalue + "，v：" + vvalue + "，t：" + tvalue);

               // return returnStr + "," + String.valueOf(GribUtil.TempK2C(tvalue).setScale(0, BigDecimal.ROUND_HALF_EVEN));
                //skyview格式grid2数据温度单位是摄氏度 。
                return returnStr + "," + String.valueOf(tvalue.setScale(0, BigDecimal.ROUND_HALF_EVEN));
            }
        }
        return null;
    }

    /**
     * 接收前台传入的参数，进行grid2数据的计算。
     * @param request
     */
    public WindResponseXML gerGrid2Response(Request request) {
        WindRequestXML windRequestXML = XmlUtil.unMarshallWindRequest(request.getRequestXML());
        WindResponseXML windResponseXML = new WindResponseXML();

        windCalcLogger.info("[Grib2Controller-gerGrid2Response(Request request)] - [开始]计算航班号（" + windRequestXML.getFlightID() + "），机尾号（" + windRequestXML.getAircraftid() + "）的风温请求数据");

        String altStr = windRequestXML.getAlt();
        String altArray[] = altStr.split("\\.");
        String cptNameStr = windRequestXML.getCptname();
        String cptNameArray[] = cptNameStr.split("\\.");
        if (altStr == null || altArray == null) {
            logger.error("请求的高度层为空！");
            return windResponseXML;
        }
        if (cptNameStr == null || cptNameArray == null) {
            logger.error("请求的航路点为空！");
            return windResponseXML;
        }

        List<FMSData> listdata = new ArrayList<FMSData>();
        int counts = 1;
        for (int i = 0; i < altArray.length; i++) {
            for (int j = 0; j < cptNameArray.length; j++) {
                counts++;
                // 核心模块处理的高度层数据单位比数据库中的小100倍
                BigDecimal grid2Alt = GribUtil.fl2hpa(new BigDecimal(altArray[i]).multiply(new BigDecimal(100)));
                String responseStr = windCalculation(cptNameArray[j], grid2Alt.setScale(2, BigDecimal.ROUND_HALF_EVEN).doubleValue(),windRequestXML.getAircraftid(),windRequestXML.getFlightID().substring(2,windRequestXML.getFlightID().length()));
                windCalcLogger.info("[Grib2Controller-gerGrid2Response(Request request)] - 高度层：" + grid2Alt.intValue() + "，航路点：" + cptNameArray[j] + "，计算出的Grib2风温数据为：" + responseStr);
                if (responseStr != null) {
                    String responseAarray[] = responseStr.split(",");
                    if (responseAarray != null || responseAarray.length == 3) {
                        FMSData dd = new FMSData();
                        dd.setAlt(altArray[i]);
                        dd.setCptname(cptNameArray[j]);
                        dd.setWindvel(responseAarray[0]);
                        dd.setWinddir(responseAarray[1]);
                        dd.setWindtep(responseAarray[2]);
                        listdata.add(dd);
                    }
                } //  if (responseStr != null) {
            } // for (int j = 0; j < cptNameArray.length; j++) {
        }
        windCalcLogger.info("[Grib2Controller-gerGrid2Response(Request request)] - [结束]计算航班号（" + windRequestXML.getFlightID() + "），机尾号（" + windRequestXML.getAircraftid() + "）的风温请求数据");
        windResponseXML.setResultcode(ErrorLevel.Success);
        windResponseXML.setCounts(counts);
        windResponseXML.setDatas(listdata);
        return windResponseXML;
    }

    /**
     * 接收前台传入的参数，进行grid2数据的计算。
     * 该函数与上面函数构成重载，功能完全相同，只是取出参数中非必要的封装（用于ContrastStatisticsService）
     * 理轮上：针对ContrastStatisticsService服务时，该函数仅计算一个高度层的所有航路风温数据，所以，下面的代码是有冗余的
     * @param windRequestXML
     */
    public List gerGrid2Response(WindRequestXML windRequestXML) {
        WindResponseXML windResponseXML = new WindResponseXML();

        windCalcLogger.info("[Grib2Controller-gerGrid2Response(WindRequestXML windRequestXML)] -[开始]计算航班号（" + windRequestXML.getFlightID() + "），机尾号（" + windRequestXML.getAircraftid() + "）的风温请求数据");

        String altStr = windRequestXML.getAlt();
        String altArray[] = altStr.split("\\.");
        String cptNameStr = windRequestXML.getCptname();
        String cptNameArray[] = cptNameStr.split("\\.");
        if (altStr == null || altArray == null) {
            logger.error("请求的高度层为空！");
            return null;
        }
        if (cptNameStr == null || cptNameArray == null) {
            logger.error("请求的航路点为空！");
            return null;
        }

        List<FMSData> listdata = new ArrayList<FMSData>();
        int counts = 1;
        for (int i = 0; i < altArray.length; i++) {
            for (int j = 0; j < cptNameArray.length; j++) {
                counts++;
                // 核心模块处理的高度层数据单位比数据库中的小100倍
                BigDecimal grid2Alt = GribUtil.fl2hpa(new BigDecimal(altArray[i]).multiply(new BigDecimal(100)));
                String responseStr = windCalculation(cptNameArray[j], grid2Alt.setScale(2, BigDecimal.ROUND_HALF_EVEN).doubleValue(),windRequestXML.getAircraftid(),windRequestXML.getFlightID().substring(2,windRequestXML.getFlightID().length()));
                windCalcLogger.info("[Grib2Controller-gerGrid2Response(WindRequestXML windRequestXML)] - 高度层：" + grid2Alt.intValue() + "，航路点：" + cptNameArray[j] + "，计算出的Grib2风温数据为：" + responseStr);
                if (responseStr != null) {
                    String responseAarray[] = responseStr.split(",");
                    if (responseAarray != null || responseAarray.length == 3) {
                        FMSData dd = new FMSData();
                        dd.setAlt(altArray[i]);
                        dd.setCptname(cptNameArray[j]);
                        dd.setWindvel(responseAarray[0]);
                        dd.setWinddir(responseAarray[1]);
                        dd.setWindtep(responseAarray[2]);
                        listdata.add(dd);
                    }
                }
            }
        }
        windCalcLogger.info("[Grib2Controller-gerGrid2Response(WindRequestXML windRequestXML)] - [结束]计算航班号（" + windRequestXML.getFlightID() + "），机尾号（" + windRequestXML.getAircraftid() + "）的风温请求数据");
        return listdata;
    }


    public static void main(String args[]) {
        Grib2Controller aaa = new Grib2Controller("CPTINFO");
        System.out.println(DateUtil.getCurrentDateTime(SysConstants.FORMAT_DATETIME_FULL));
       // System.out.println(aaa.windCalculation("P202", GribUtil.fl2hpa(BigDecimal.valueOf(18000)).doubleValue()));
        System.out.println(DateUtil.getCurrentDateTime(SysConstants.FORMAT_DATETIME_FULL));

    }

}
